﻿namespace CloudNinja.Metering.Tests.DataRepository
{
    using System;
    using System.Collections.Generic;
    using System.Data.SqlClient;
    using System.Linq;

    using CloudNinja.Metering.Data.Models;

    using Dapper;

    using Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling;

    using Xunit;

    public class MeteringRepositoryFixture
    {

        protected const string ConnectionString = "Data Source=.; Initial Catalog=cnmb; Integrated Security=SSPI;";

        protected SqlConnection TestConnection;

        protected readonly DateTimeOffset PresentHour;

        protected readonly DateTimeOffset TenMinutesLater;

        protected readonly DateTimeOffset TenMinutesAgo;

        protected readonly DateTimeOffset AnHourAgo;

        protected readonly DateTimeOffset AnHourLater;

        protected readonly DateTimeOffset NextDay;

        protected readonly RetryPolicy<SqlDatabaseTransientErrorDetectionStrategy> sqlRetryPolicy;

        public MeteringRepositoryFixture()
        {
            this.PresentHour = DateTime.Now;
            this.TenMinutesLater = this.PresentHour.AddMinutes(10);
            this.TenMinutesAgo = this.PresentHour.AddMinutes(-10);
            this.AnHourAgo = this.PresentHour.AddHours(-1);
            this.AnHourLater = this.PresentHour.AddHours(1);
            this.NextDay = this.PresentHour.AddDays(1);

            var strategy = new FixedInterval("fixed", 10, TimeSpan.FromSeconds(3));

            this.sqlRetryPolicy = new RetryPolicy<SqlDatabaseTransientErrorDetectionStrategy>(strategy);
        }

        protected IEnumerable<MonthlyView> GetTestMonthlyViewData()
        {
            var result = new List<MonthlyView>();

            using (this.TestConnection = new SqlConnection(MeteringRepositoryFixture.ConnectionString))
            {
                this.TestConnection.Open();

                var cmd =
                    new SqlCommand(
                        "select TenantId, MeterTypeId, Year, Month, TimePeriodEnd, Value from MonthlyView",
                        this.TestConnection);

                var reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    result.Add(
                        new MonthlyView
                        {
                            TenantId = reader["TenantId"].ToString(),
                            MeterTypeId = reader["MeterTypeId"].ToString(),
                            Year = (int)reader["Year"],
                            Month = (int)reader["Month"],
                            TimePeriodEnd = (DateTime)reader["TimePeriodEnd"],
                            Value = (double)reader["Value"]
                        });
                }
            }

            return result;
        }

        protected void AddMeterDataForSameTenantForOneDay()
        {
            using (this.TestConnection = new SqlConnection(MeteringRepositoryFixture.ConnectionString))
            {
                this.TestConnection.Open();

                //const string MeterTypesInsert =
                //    @"INSERT INTO MeterType ([Id],[Name],[Description],[AggregateType],[UnitOfMeasure], [Weight]) VALUES (@typeId, 'Test Type', 'Test Type', 'sum', 'kb', 3)";
                //var meterTypeData = new[] { new { typeId = "bwe" }, new { typeId = "dbs" }, new { typeId = "stg" } };
                //this.TestConnection.Execute(MeterTypesInsert, meterTypeData);

                const string InsertQuery =
                    @"INSERT INTO MeterData(TenantId, MeterTypeId, TimePeriod, Value, Count) VALUES (@tenantId, @meterTypeId, @timePeriod, @value, @count)";


                var meterData = new[]
                                    {
                                        new
                                            {
                                                tenantId = "testtenant1",
                                                meterTypeId = "bwe",
                                                timePeriod = this.PresentHour.ToUniversalTime(),
                                                value = 1,
                                                count = 1
                                            },
                                        new
                                            {
                                                tenantId = "testtenant1",
                                                meterTypeId = "dbs",
                                                timePeriod = this.PresentHour.ToUniversalTime(),
                                                value = 1,
                                                count = 1
                                            }
                                    };

                this.TestConnection.Execute(InsertQuery, meterData);
            }
        }

        protected void AddMeterDataForSameTenantForTwoDays()
        {
            using (this.TestConnection = new SqlConnection(MeteringRepositoryFixture.ConnectionString))
            {
                this.TestConnection.Open();

                const string InsertQuery =
                    @"INSERT INTO MeterData(TenantId, MeterTypeId, TimePeriod, Value, Count) VALUES (@tenantId, @meterTypeId, @timePeriod, @value, @count)";

                var meterData = new[]
                                    {
                                        new
                                            {
                                                tenantId = "testtenant1",
                                                meterTypeId = "bwe",
                                                timePeriod = this.PresentHour,
                                                value = 1,
                                                count = 1
                                            },
                                        new
                                            {
                                                tenantId = "testtenant1",
                                                meterTypeId = "dbs",
                                                timePeriod = this.NextDay,
                                                value = 1,
                                                count = 1
                                            }
                                    };

                this.TestConnection.Execute(InsertQuery, meterData);
            }
        }

        protected IEnumerable<MeterData> GetTestMeterData()
        {
            var result = new List<MeterData>();

            using (this.TestConnection = new SqlConnection(MeteringRepositoryFixture.ConnectionString))
            {
                this.TestConnection.Open();

                var cmd =
                    new SqlCommand(
                        "select TenantId, MeterTypeId, TimePeriod, Value, Count from MeterData",
                        this.TestConnection);

                var reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    result.Add(
                        new MeterData
                        {
                            TenantId = reader["TenantId"].ToString(),
                            MeterTypeId = reader["MeterTypeId"].ToString(),
                            Value = (double)reader["Value"],
                            Count = (int)reader["Count"],
                            TimePeriod = (DateTime)reader["TimePeriod"]
                        });
                }
            }

            return result;
        }

        protected void RemoveMeterData()
        {
            using (this.TestConnection = new SqlConnection(MeteringRepositoryFixture.ConnectionString))
            {
                this.TestConnection.Open();
                this.TestConnection.Execute("DELETE FROM MeterData WHERE TenantId like 'testtenant%'");
                //this.TestConnection.Execute("DELETE FROM MeterType WHERE Id LIKE 'TS%'");
            }
        }
    }
}